package oplogd

import (
	"time"

	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/common"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/ddd"
)

const (
	// OpLogName 操作日志聚合根模块名称
	OpLogName = DomainID
)

func initOpLog(d ddd.Domain, repo OpLogRepo) {
	car := &oplogAggregateRoot{}
	car.Init(car, d, "oplog")
	repo.Init(repo, car, "oplog")
	// ddd.RegAggregateRoot(d, car)
	// ddd.SetRepoForARoot(car, repo)

}

// OpLogRepo 操作日志仓储
type OpLogRepo interface {
	ddd.Repository
	GetOpLog(ctx ddd.Context, id string) *OpLogAggregate
	// 新增操作日志
	// id 返回信息操作日志的唯一标识
	AddOpLog(ctx ddd.Context, oplog *OpLogEntity) (err error)
	// 分页获取操作日志信息列表：根据唯一标识获取下一页指定数量的操作日志信息实体集合
	// total 总数量
	QueryPage(ctx ddd.Context, is OpLogSearch, pi common.PageInfo) (npi common.PageResult, result []OpLogAggregate, err error)
}

// OpLogSearch 操作日志查询条件
// 指定 Mode SrcID SrcType ，返回某个操作日志源的操作日志信息列表
// 指定 UID 指定摸个用户的操作日志信息列表
// 指定 UID Mode 指定用户的某个操作日志模式的操作日志信息列表
// 指定 UID Mode SrcType 指定用户的某个操作日志源类型的操作日志信息列表
type OpLogSearch struct {
	UID       string `json:"uid,omitempty"`   // 操作日志用户
	StartTime string `json:"start,omitempty"` // 操作日志ID
	EndTime   string `json:"end,omitempty"`   // 操作日志模式

}

// OpLogAggregateRoot 操作日志聚合根
// 一个操作日志实体（信息，评论，栏目专题等等）只能有一种操作日志方式，或者星级，或者点赞或者喜欢不喜欢
type OpLogAggregateRoot interface {
	ddd.AggregateRoot
	Repo() OpLogRepo
	GetOpLog(ctx ddd.Context, id string) *OpLogAggregate
	// 进行信息操作日志
	// id 返回信息操作日志的唯一标识
	AddOpLog(ctx ddd.Context, ol *OpLogEntity) (err error)
	// 分页获取操作日志信息列表：根据唯一标识获取下一页指定数量的操作日志信息实体集合
	// total 总数量
	QueryPage(ctx ddd.Context, is OpLogSearch, pi common.PageInfo) (npi common.PageResult, result []OpLogAggregate, err error)
}

// OpLogAggregate 操作日志聚合
type OpLogAggregate struct {
	ddd.BaseAggregate
	OpLogEntity `json:"oplog_entity,omitempty"`
}

// Repo 获取聚合根对应的仓储
func (i OpLogAggregate) Repo() OpLogRepo {
	repo := i.Repository()
	if repo != nil {
		if irepo, ok := repo.(OpLogRepo); ok {
			return irepo
		}
	}
	return nil
}

// NewValidity 新增时校验
func (i OpLogAggregate) NewValidity() error {
	return nil
}

// OpLogEntity 操作日志实例
type OpLogEntity struct {
	ID         string      `json:"id,omitempty"`          // 日志唯一编号
	Action     string      `json:"action,omitempty"`      // 操作接口动作
	Desc       string      `json:"desc,omitempty"`        // 描述
	Module     string      `json:"module,omitempty"`      // 模块
	UID        string      `json:"uid,omitempty"`         // 用户编号
	URL        string      `json:"url,omitempty"`         // URL
	Head       interface{} `json:"head,omitempty"`        // 头信息
	OpTime     time.Time   `json:"op_time,omitempty"`     // 操作时间
	UseTime    int64       `json:"use_time,omitempty"`    // 用时，单位毫秒
	IP         string      `json:"ip,omitempty"`          // ip
	Agent      string      `json:"agent,omitempty"`       // 浏览器代理
	Refer      string      `json:"refer,omitempty"`       // refer 引用至
	HTTPStatus int         `json:"http_status,omitempty"` // http状态码
	Status     int         `json:"status,omitempty"`      // 业务状态
	Input      interface{} `json:"input,omitempty"`       // 输入数据（仅记录最多4096字节）
	Output     interface{} `json:"output,omitempty"`      // 输出数据（仅记录最多4096字节）
	Err        string      `json:"err,omitempty"`         // 记录错误信息
}

type oplogAggregateRoot struct {
	ddd.BaseAggregateRoot
}

func (i oplogAggregateRoot) Repo() OpLogRepo {
	if repo, ok := i.Repository().(OpLogRepo); ok {
		return repo.(OpLogRepo)
	}
	return nil
}
func (i *oplogAggregateRoot) GetOpLog(ctx ddd.Context, id string) *OpLogAggregate {
	ia := i.Repo().GetOpLog(ctx, id)
	ia.Init(ia, i, OpLogName+":"+id)
	return ia
}

// 新增操作日志
func (i *oplogAggregateRoot) AddOpLog(ctx ddd.Context, ol *OpLogEntity) (err error) {
	return i.Repo().AddOpLog(ctx, ol)
}

// 分页获取操作日志信息列表：根据唯一标识获取下一页指定数量的操作日志信息实体集合
// total 总数量
func (i oplogAggregateRoot) QueryPage(ctx ddd.Context, is OpLogSearch, pi common.PageInfo) (npi common.PageResult, result []OpLogAggregate, err error) {
	return i.Repo().QueryPage(ctx, is, pi)
}

// NewOpLogAggregate 创建一个交互聚合
func (i *oplogAggregateRoot) NewOpLogAggregate(ol OpLogEntity) *OpLogAggregate {
	return &OpLogAggregate{
		OpLogEntity: ol,
	}
}
